use rayon::prelude::*;
use std::time::{SystemTime, Duration};

fn main() {
	let mut vec1 = vec![1, 3, 5, 8, 0, -1];
	// SystemTime即可以当时间戳，它还同时具有Stopwatch的功能，即直接调用start.elapsed()就能获取从创建start开始经过了多长时间
	// 它内部其实就是再次获取一次now()然后相减得到
	let start = SystemTime::now();
	let duration0 = start.duration_since(std::time::UNIX_EPOCH).unwrap();
	// Vec<_>的意思是我只给出大类型是Vec，具体元素的类型仍然由编译器去推断？？（反正换成Vec<i32>结果一样）
	// 这个其实就类似java8里的parallelStream()，而且map也是最终按顺序get元素（但是map过程是并行的）
	let x: Vec<_> = vec1.par_iter().map(|e| {
		std::thread::sleep(Duration::from_secs(1));
		e + 1
	}).collect();

	// 指从UNIX_EPOCH开始start这个时间戳经过了多长时间
	let duration = start.duration_since(std::time::UNIX_EPOCH).unwrap();
	let end = SystemTime::now();
	println!("{:?}, {:?}, {:?}, {:?}", x, duration.as_secs_f64(), duration0, start.elapsed().unwrap().as_millis());
	std::thread::sleep(Duration::from_secs(1));
	println!("{}", start.elapsed().unwrap().as_millis());

	// TODO 这里的逻辑是如果vec1是空Vec，那么这里sum()返回的是0（感觉不是很好，为什么不返回Option<i32>？）
	let sum: i32 = vec1.par_iter().map(|e| e * e).sum();
	println!("ttt - {}", sum);
	// TODO 好吧，标准库也是这个逻辑，算了，反正运算前也是可以自己先判断Vec长度的；
	let sum: i32 = vec![].iter().sum();
	println!("{}", sum);
	vec1.par_iter().for_each(|e| print!("#{}", e));

	// 可以修改vec1的元素值，这里必须用par_iter_mut()，用par_iter()不行
	// 原理就是虽然vec1是mut，但是par_iter()方法里是&self 而非 &mut self，所以会报错
	// ，可以参考下面的vec1[0] = 8可以，但是vec2[0] = 8报错
	// TODO 即可变Vec可以产生不可变的引用，但是不可变Vec无法产生可变引用；
	vec1.par_iter_mut().for_each(|e| *e += 8);
	println!("{:?}", vec1);
	let vec2 = &vec1;
	println!("{:?}", vec2);
	vec1[0] = 8;
	// 报错
	//vec2[0] = 8;
	let vec3 = vec![8, 9, 3];
	// 这里难道不是应该报错吗？还是说是rust的bug？（虽然vec4[0] = 9会报错，但是感觉这里就应该要报错啊；确实不会报错。。）
	// TODO 这里let mut是指vec4这个引用的值可变，而不是说它引用的对象可变，这是两个概念
	// TODO 如果这里没有左边的mut那么下面的vec4 = &vec1就会报错；
	// TODO 总结，变量可变，如果变量是引用则还有 其引用对象是否可变 这两个mut的概念；
	let mut vec4 = &vec3;
	//vec4[0] = 9;
	// TODO 好吧不是bug，它们概念不一样，方法是: &mut，而这里是let mut
	//test(&vec3)

	// TODO 好吧，这里定义是获取的是mut引用还是非mut引用取决于右值而非左值，即左边不写let mut vec5，由于右边是&mut vec1
	// TODO 那么vec5也是mut的
	let vec5 = &mut vec1;
	vec5[3] = 9;

	// TODO 由于上面的vec4是可变的变量（变量类型是引用），所以这里可以对其重新赋值
	vec4 = &vec1;

	// TODO 但其实非引用变量也是存在两个mut概念的
	let vec6 = vec![3, 4];
	// TODO 第一个概念，vec6对应的对象不可变，所以vec6[0] = 8;报错
	//vec6[0] = 8;
	// 第二个mut概念是vec6不能重新赋值，所以下面也报错；
	//vec6 = vec![9, 8]

	// TODO 但是引用类型的变量特殊在于 这两个mut概念 可以分开（而且第二层mut由右值决定）；而普通变量则是合二为一的，要么都可变，要么都不可变；

	println!("{:?}", fib(32));

	// futures 使用，futures的作用其实就类似其他语言里的线程池（注意，目前rust标准库里没有线程池）
	// async {..}是产生Future对象；这里用的是默认的线程池，还可以通过futures::executor::ThreadPool::new().unwrap()产生自己的Executor
	futures::executor::block_on(async {
		// async块会返回Future
		println!("{}", "fsjklfj");
	});
	// 貌似是30个Worker一次性启动？，而且pool貌似没有类似java commit之类的手动运行task或future的方法；
	// 还有为什么不像java一样可以设置coreSize和maxSize？
	let pool = futures::executor::ThreadPoolBuilder::new().pool_size(30).name_prefix("custom-pool-").after_start(|a| {
		println!("task started");
	}).create().unwrap();

	// 没有这个方法。。
	/*pool.run(async {
		println!("UUU");
	})*/

	let testm: Vec<_> = vec![3, 4];
	let x1: Vec<_> = testm.into_iter().map(|e| e + 2).collect();
	// 由于用的是into_iter()，所以此时已经不能再用testm了，但是换成iter或iter_mut是可以的，因为into_iter是会获得所有权的元素而非其引用
	println!("{:?}", testm);
	println!("$$${:?}", x1);
}

fn test(uu: &mut Vec<i32>) {

}

/// 斐波那契数列，n是第几个元素的意思
fn fib(n: u32) -> u64 {
	if n < 2 {
		return n as u64;
	}
	// join是将n个计算式 “并行” 执行，并且将它们的结果按计算式顺序转换为元素，有点像par_iter().map(...)
	let (a, b) = rayon::join(
		|| fib(n - 1), || fib(n - 2)
	);
	a + b
}
